package org.codefilarete.stalactite.dsl.entity;

import java.util.Collection;
import java.util.function.Supplier;

import org.codefilarete.reflection.SerializablePropertyAccessor;
import org.codefilarete.reflection.SerializablePropertyMutator;
import org.codefilarete.stalactite.dsl.relation.ManyToOneEntityOptions;
import org.codefilarete.stalactite.dsl.relation.ManyToOneOptions;
import org.codefilarete.stalactite.sql.ddl.structure.Column;

public interface FluentMappingBuilderManyToOneOptions<C, I, O, S extends Collection<C>>
		extends FluentEntityMappingBuilder<C, I>, ManyToOneEntityOptions<C, O, S> {
	
	@Override
	FluentMappingBuilderManyToOneOptions<C, I, O, S> mandatory();
	
	/**
	 * Defines combiner of current entity with target entity. This is a more fine-grained way to define how to combine current entity with target
	 * entity than {@link ManyToOneOptions#reverseCollection(SerializablePropertyAccessor)} : sometimes a method already exists in entities to fill the relation instead of
	 * calling getter + Collection.add. This method is here to benefit from it.
	 * This method has no consequence on database mapping since it only interacts in memory.
	 *
	 * @param reverseLink opposite owner of the relation
	 * @return the global mapping configurer
	 */
	@Override
	FluentMappingBuilderManyToOneOptions<C, I, O, S> reverselySetBy(SerializablePropertyMutator<O, C> reverseLink);
	
	/**
	 * Defines reverse collection accessor.
	 * Used to fill an (in-memory) bi-directionality.
	 * This method has no consequence on database mapping since it only interacts in memory.
	 *
	 * @param collectionAccessor opposite owner of the relation
	 * @return the global mapping configurer
	 */
	@Override
	FluentMappingBuilderManyToOneOptions<C, I, O, S> reverseCollection(SerializablePropertyAccessor<O, S> collectionAccessor);
	
	/**
	 * Defines reverse collection mutator.
	 * Used to fill an (in-memory) bi-directionality.
	 * This method has no consequence on database mapping since it only interacts in memory.
	 *
	 * @param collectionMutator opposite setter of the relation
	 * @return the global mapping configurer
	 */
	@Override
	FluentMappingBuilderManyToOneOptions<C, I, O, S> reverseCollection(SerializablePropertyMutator<O, S> collectionMutator);
	
	/**
	 * Defines the factory of reverse collection. If not defined and collection is found null, the collection is set with a default value.
	 * This method has no consequence on database mapping since it only interacts in memory.
	 *
	 * @param collectionFactory opposite collection factory
	 * @return the global mapping configurer
	 */
	@Override
	FluentMappingBuilderManyToOneOptions<C, I, O, S> reverselyInitializeWith(Supplier<S> collectionFactory);
	
	@Override
	FluentMappingBuilderManyToOneOptions<C, I, O, S> cascading(RelationMode relationMode);
	
	@Override
	FluentMappingBuilderManyToOneOptions<C, I, O, S> fetchSeparately();
	
	@Override
	FluentMappingBuilderManyToOneOptions<C, I, O, S> columnName(String columnName);

	/**
	 * {@inheritDoc}
	 * Declaration overridden to adapt the return type to this class.
	 *
	 * @param reverseLink foreign key column referencing the target entity key
	 * @return the global mapping configurer
	 */
	@Override
	FluentMappingBuilderManyToOneOptions<C, I, O, S> mappedBy(Column<?, ?> reverseLink);
}
